// [file: CalcInterpreter.g, started: 22-Apr-2008]
//
// Calc - Simple calculator with memory variables.
// CalcInterpreter.g: interpreter
//
// @author   Theo Ruys
// @version  2008.04.22

tree grammar CalcInterpreter;

options {
    tokenVocab=Calc;                    // import tokens from Calc.tokens
    ASTLabelType=CommonTree;            // AST nodes are of type CommonTree
}

@header {
package vb.week3.calc;
import java.util.Map;
import java.util.HashMap;
import java.lang.*;
}

@members { 
    private Map<String,Integer> store = new HashMap<String,Integer>();   
}

program
    :   ^(PROGRAM (declaration | statement)+)
    ;
    
declaration
    :   ^(VAR id=IDENTIFIER type)
            { store.put($id.text, 0); } 
    ;

statements
    :   statement+
    ;
    
statement 
    :   ^(PRINT v=compound_expr)
            { System.out.println("" + v);   }
    |   ^(SWAP x=IDENTIFIER y=IDENTIFIER){   
            
            int temp = store.get($x.text);
            store.put($x.text,store.get($y.text));
            store.put($y.text,temp);
            }
    |   compound_expr
    |   dowhile_stat
    ;
    
    
dowhile_stat
@init { int ix = input.index(); }
    : ^(DO statements WHILE v=compound_expr) { if (v != 0) { input.rewind(ix); }	      }
    ;
      
compound_expr returns [int val = 0;] 
    :   ^(BECOMES id=IDENTIFIER v=compound_expr)  { val = v; store.put($id.text, v); } // System.out.println($id.text + " " + v); 
    |   ^(IF x=compound_expr y=compound_expr z=compound_expr)  {if(x!=0){val = y;} else{val = z;}}
    |   ^(LESSTHAN x=compound_expr y=compound_expr)     {if(x<y)  {val = 1;}  else{val = 0;}}
    |   ^(LESSEQUAL x=compound_expr y=compound_expr)    {if(x<=y) {val = 1;}  else{val = 0;}}
    |   ^(GREATERTHAN x=compound_expr y=compound_expr)  {if(x>y)  {val = 1;}  else{val = 0;}}
    |   ^(GREATEREQUAL x=compound_expr y=compound_expr) {if(x>=y) {val = 1;}  else{val = 0;}}
    |   ^(EQUAL x=compound_expr y=compound_expr)        {if(x==y) {val = 1;}  else{val = 0;}}
    |   ^(NOTEQUAL x=compound_expr y=compound_expr)     {if(x!=y) {val = 1;}  else{val = 0;}}
    |   ^(PLUS x=compound_expr y=compound_expr)   { val = x + y;  } // System.out.println("+ " + x + " " + y); 
    |   ^(MINUS x=compound_expr y=compound_expr)  { val = x - y;  } // System.out.println("- " + x + " " + y); 
    |   ^(TIMES x=compound_expr y=compound_expr)    { val = x * y;  } // System.out.println("* " + x + " " + y); 
    |   ^(DIVIDEBY x=compound_expr y=compound_expr) { // System.out.println("/ " + x + " " + y); 
                                        if(y == 0)
                                          throw new IllegalArgumentException("Divide by zero not allowed");
                                        val = x / y;
                                      }
    |   z=operand                     { val = z;      }
    ;
    
operand returns [int val = 0]
    :   id=IDENTIFIER   { val = store.get($id.text);       } 
    |   n=NUMBER        { val = Integer.parseInt($n.text); }
    ;
    
type
    :   INTEGER
    ;
